package com.logisticsinquiry.android.logic.network
import com.google.gson.Gson
import com.logisticsinquiry.android.QueryApplication
import com.logisticsinquiry.android.logic.model.ExpressQueryResponse
import com.logisticsinquiry.android.logic.model.ShipperCodeResponse
import com.logisticsinquiry.android.logic.network.APICallbackListener
import java.util.*
import java.io.*
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import java.security.MessageDigest
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine


/**
 *
 * 快递鸟物流轨迹即时查询接口
 *
 * @技术QQ群: 456320272
 * @see: http://www.kdniao.com/YundanChaxunAPI.aspx
 * @copyright: 深圳市快金数据技术服务有限公司
 *
 * DEMO中的电商ID与私钥仅限测试使用，正式环境请单独注册账号
 * 单日超过500单查询量，建议接入我方物流轨迹订阅推送接口
 *
 * ID和Key请到官网申请：http://www.kdniao.com/ServiceApply.aspx
 */
class KdniaoTrackQueryAPI {
    //电商ID
    private lateinit var response :String

    /**
     * Json方式 查询订单物流轨迹
     * @throws Exception
     */
    @Throws(Exception::class)
    suspend fun expressQuery(shipperCode: String, logisticCode: String): ExpressQueryResponse {
        val requestData =
            "{'OrderCode':'','ShipperCode':'$shipperCode','LogisticCode':'$logisticCode'}"
        val params: MutableMap<String, String> =
            HashMap()
        params["RequestData"] = urlEncoder(requestData, "UTF-8")
        params["EBusinessID"] = QueryApplication.EBusinessID
        params["RequestType"] = "1002"
        val dataSign = encrypt(requestData, QueryApplication.AppKey, "UTF-8")
        params["DataSign"] = urlEncoder(dataSign, "UTF-8")
        params["DataType"] = "2"

        //根据公司业务处理返回的信息......
        val result = request(QueryApplication.ReqURL, params)
        return Gson().fromJson(result,ExpressQueryResponse::class.java)
        //返回带有信息的Response类
    }

    @Throws(Exception::class)
    suspend fun searchShipper(logisticCode: String): ShipperCodeResponse {
/*        Log.v("调试信息进入API，调用方法","yes")*/
        val requestData =
            "{'LogisticCode':'$logisticCode'}"
        val params: MutableMap<String, String> =
            HashMap()
        params["RequestData"] = urlEncoder(requestData, "UTF-8")
        params["EBusinessID"] = QueryApplication.EBusinessID
        params["RequestType"] = "2002"
        val dataSign = encrypt(requestData, QueryApplication.AppKey, "UTF-8")
        params["DataSign"] = urlEncoder(dataSign, "UTF-8")
        params["DataType"] = "2"
        //根据公司业务处理返回的信息......
 /*       Log.v("调试信息进入API，调用方法","yes")*/
        val result = request(QueryApplication.ReqURL, params)
        return Gson().fromJson(result, ShipperCodeResponse::class.java)
        //返回带有信息的Response类
    }

    /**
     * MD5加密
     * @param str 内容
     * @param charset 编码方式
     * @throws Exception
     */
    @Throws(Exception::class)
    private fun MD5(str: String, charset: String): String {
        val md = MessageDigest.getInstance("MD5")
        md.update(str.toByteArray(charset(charset)))
        val result = md.digest()
        val sb = StringBuffer(32)
        for (i in result.indices) {
            val `val`: Int = result[i].toInt() and 0xff.toInt()
            if (`val` <= 0xf) {
                sb.append("0")
            }
            sb.append(Integer.toHexString(`val`))
        }
        return sb.toString().toLowerCase()
    }

    /**
     * base64编码
     * @param str 内容
     * @param charset 编码方式
     * @throws UnsupportedEncodingException
     */
    @Throws(UnsupportedEncodingException::class)
    private fun base64(str: String, charset: String): String {
        return base64Encode(str.toByteArray(charset(charset)))
    }

    @Throws(UnsupportedEncodingException::class)
    private fun urlEncoder(str: String, charset: String): String {
        return URLEncoder.encode(str, charset)
    }

    /**
     * 电商Sign签名生成
     * @param content 内容
     * @param keyValue Appkey
     * @param charset 编码方式
     * @throws UnsupportedEncodingException ,Exception
     * @return DataSign签名
     */
    @Throws(UnsupportedEncodingException::class, Exception::class)
    private fun encrypt(
        content: String,
        keyValue: String?,
        charset: String
    ): String {
        return if (keyValue != null) {
            base64(MD5(content + keyValue, charset), charset)
        } else base64(MD5(content, charset), charset)
    }

    /**
     * 向指定 URL 发送POST方法的请求
     * @param url 发送请求的 URL
     * @param params 请求的参数集合
     * @return 远程资源的响应结果
     */
    private fun sendPost(
        url: String,
        params: Map<String, String>?,
        listener: APICallbackListener
    ) {
        var out: OutputStreamWriter? = null
        var `in`: BufferedReader? = null
        val result = StringBuilder()
        try {
            val realUrl = URL(url) //传入地址
            val conn = realUrl.openConnection() as HttpURLConnection //获取HttpURLConnection的实例
            // 发送POST请求必须设置如下两行
            conn.doOutput = true
            conn.doInput = true
            // POST方法
            conn.requestMethod = "POST"
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*")
            conn.setRequestProperty("connection", "Keep-Alive")
            conn.setRequestProperty(
                "user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"
            )
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
            conn.connect()
            // 获取URLConnection对象对应的输出流
            out = OutputStreamWriter(conn.outputStream, "UTF-8")
            // 发送请求参数
            if (params != null) {
                val param = StringBuilder()
                for ((key, value) in params) {
                    if (param.length > 0) {
                        param.append("&")
                    }
                    param.append(key)
                    param.append("=")
                    param.append(value)
                    //System.out.println(entry.getKey()+":"+entry.getValue());
                }
                //System.out.println("param:"+param.toString());
                out.write(param.toString())
            }
            // flush输出流的缓冲
            out.flush()
            // 定义BufferedReader输入流来读取URL的响应
            `in` = BufferedReader(
                InputStreamReader(conn.inputStream, "UTF-8")
            )
            var line: String?
            while (`in`.readLine().also { line = it } != null) {
                result.append(line)
            }
            listener.onFinish(result.toString())
        } catch (e: Exception) {
            e.printStackTrace()
        } //使用finally块来关闭输出流、输入流
        finally {
            try {
                out?.close()
                `in`?.close()
            } catch (ex: IOException) {
                ex.printStackTrace()
            }
        }
    }

    companion object {

        private val base64EncodeChars = charArrayOf(
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
            'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
            'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
            'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
            'w', 'x', 'y', 'z', '0', '1', '2', '3',
            '4', '5', '6', '7', '8', '9', '+', '/'
        )

        fun base64Encode(data: ByteArray): String {
            val sb = StringBuffer()
            val len = data.size
            var i = 0
            var b1: Int
            var b2: Int
            var b3: Int
            while (i < len) {
                b1 = data[i++].toInt() and 0xff.toInt()
                if (i == len) {
                    sb.append(base64EncodeChars[b1 ushr 2])
                    sb.append(base64EncodeChars[b1 and 0x3 shl 4])
                    sb.append("==")
                    break
                }
                b2 = data[i++].toInt() and 0xff.toInt()
                if (i == len) {
                    sb.append(base64EncodeChars[b1 ushr 2])
                    sb.append(base64EncodeChars[b1 and 0x03 shl 4 or (b2 and 0xf0 ushr 4)])
                    sb.append(base64EncodeChars[b2 and 0x0f shl 2])
                    sb.append("=")
                    break
                }
                b3 = data[i++].toInt() and 0xff.toInt()
                sb.append(base64EncodeChars[b1 ushr 2])
                sb.append(base64EncodeChars[b1 and 0x03 shl 4 or (b2 and 0xf0 ushr 4)])
                sb.append(base64EncodeChars[b2 and 0x0f shl 2 or (b3 and 0xc0 ushr 6)])
                sb.append(base64EncodeChars[b3 and 0x3f])
            }
            return sb.toString()
        }
    }

    suspend fun request(
        url: String,
        params: Map<String, String>?):String{
        return suspendCoroutine { continuation ->
            sendPost(url, params, object : APICallbackListener {
                override fun onFinish(response: String) {
                    continuation.resume(response)
                }

                override fun onError(e: java.lang.Exception) {
                    continuation.resumeWithException(e)
                }
            })
        }
    }
}